﻿using FileStorage.Common;
using FileStorage.Model.Dto;
using FileStorage.Models;
using FileStorage.Models.Dto;
using FileStorage.Models.Entity;
using FileStorage.Models.Enum;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace FileStorage.Controllers
{
    [Route("homeController/[action].ajax")]
    [ApiController]
#if !DEBUG
    [ApiExplorerSettings(IgnoreApi = true)]
#endif
    public class ApiHomeController : ControllerBase
    {
        private static int SELECT_STEP = 256;

        private readonly IWebHostEnvironment _hostEnvironment;
        private readonly ILogger<ApiHomeController> _logger;

        private readonly RSAKeyUtil _rsa;

        public ApiHomeController(IWebHostEnvironment hostEnvironment, ILogger<ApiHomeController> logger, RSAKeyUtil rsa)
        {
            _hostEnvironment = hostEnvironment;
            _logger = logger;
            _rsa = rsa;
        }

        [HttpGet, HttpPost]
        public string GetServerOS()
        {
            return SystemUtil.getOSName();
        }

        [HttpGet, HttpPost]
        public PublicKeyInfo GetPublicKey()
        {
            var res = new PublicKeyInfo();
            res.publicKey = _rsa.GetPublicKey();
            res.time = SystemUtil.currentTimeMillis();
            return res;
        }

        [HttpPost]
        public string DoLogin([FromForm] string encrypted, [FromForm] string vercode)
        {
            try
            {
                var loginInfoStr = _rsa.Decrypt(_rsa.GetPrivateKey(), encrypted);
                LoginInfo info = JsonConvert.DeserializeObject<LoginInfo>(loginInfoStr.Replace("\\\\", "\\\\\\\\"));
#if !DEBUG
                if (SystemUtil.currentTimeMillis() - Convert.ToInt64(info.time) > 3000L)
                    return "error";
#endif
                if (!string.Equals("Close", ServerConfig.VCLevel, StringComparison.CurrentCultureIgnoreCase))
                {
                    string reqVerCode = vercode;
                    string trueVerCode = HttpContext.Session.GetString("VERCODE");
                    HttpContext.Session.Remove("VERCODE");
                    if (string.IsNullOrEmpty(reqVerCode) || string.IsNullOrEmpty(trueVerCode) || !string.Equals(reqVerCode, trueVerCode, StringComparison.CurrentCultureIgnoreCase))
                        return "needsubmitvercode";
                }

                // check account
                if (true)
                {
                    HttpContext.Session.SetString("ACCOUNT", info.accountId);
                    return "permitlogin";
                }
                else
                    return "accountpwderror";
            }
            catch (Exception e)
            {
                return "error";
            }
        }

        [HttpGet("/homeController/[action].do")]
        public IActionResult GetNewVerCode()
        {
            if (!string.Equals("Close", ServerConfig.VCLevel, StringComparison.CurrentCultureIgnoreCase))
            {
                var captchaCode = CaptchaHelper.GetCaptchaCode();
                byte[] bytes = CaptchaHelper.CreateCaptchaImage(captchaCode);
                HttpContext.Session.SetString("VERCODE", captchaCode);
                return File(bytes, @"image/png");
            }
            return NotFound();
        }

        [HttpPost]
        public string DoChangePassword([FromForm] string encrypted, [FromForm] string vercode)
        {
            if (!ServerConfig.AllowChangePassword)
                return "illegal";
            string account = HttpContext.Session.GetString("ACCOUNT");
            try
            {
                var changePasswordInfoStr = _rsa.Decrypt(_rsa.GetPublicKey(), encrypted);
                ChangePasswordInfo info = JsonConvert.DeserializeObject<ChangePasswordInfo>(changePasswordInfoStr.Replace("\\\\", "\\\\\\\\"));
#if !DEBUG
                if (SystemUtil.currentTimeMillis() - Convert.ToInt64(info.time) > 3000L)
                    return "error";
#endif
                if (ServerConfig.VCLevel != nameof(ServerConfig.VCLevel))
                {
                    string reqVerCode = vercode;
                    string trueVerCode = HttpContext.Session.GetString("VERCODE");
                    HttpContext.Session.Remove("VERCODE");
                    if (string.IsNullOrEmpty(reqVerCode) || string.IsNullOrEmpty(trueVerCode) || !string.Equals(reqVerCode, trueVerCode, StringComparison.CurrentCultureIgnoreCase))
                        return "needsubmitvercode";
                }

                // check account password
                if (true)
                {
                    if (!string.IsNullOrEmpty(info.newPwd) && info.newPwd.Length > 3 && info.newPwd.Length <= 32)
                    {
                        // change password
                        return "success";
                    }
                    return "invalidnewpwd";
                }
                else
                    return "oldpwderror";
            }
            catch (Exception e)
            {
                return "cannotchangepwd";
            }

        }

        [HttpPost]
        public string GetFolderView([FromForm] string fid)
        {
            if (string.IsNullOrEmpty(fid))
                return "ERROR";

            using var cn = new DapperHelper();

            var vf = FolderDao.queryById(fid, cn);
            if (vf == null)
                return "NOT_FOUND";
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (!accessFolder(vf, account))
                return "notAccess";
            var fv = new FolderView();
            fv.selectStep = SELECT_STEP;
            fv.folder = vf;
            fv.parentList = FolderDao.getParentList(fid, cn);
            long foldersOffset = FolderDao.countByParentId(fid, cn);
            fv.foldersOffset = foldersOffset;
            long fOffset = foldersOffset - SELECT_STEP;
            List<Folder> folders = FolderDao.queryByParentIdSection(fid, fOffset > 0 ? fOffset : 0L, SELECT_STEP, cn);
            List<Folder> fs = new List<Folder>();
            foreach (var f in folders)
            {
                if (accessFolder(f, account))
                    fs.Add(f);
            }
            fv.folderList = fs;
            long filesOffset = FileDao.countByParentFolderId(fid, cn);
            fv.filesOffset = filesOffset;
            long fiOffset = filesOffset - SELECT_STEP;
            fv.fileList = FileDao.queryByParentFolderIdSection(fid, fiOffset > 0 ? fiOffset : 0L, SELECT_STEP, cn);
            if (account != null)
                fv.account = account;
            fv.allowChangePassword = ServerConfig.AllowChangePassword ? "true" : "false";
            fv.allowSignUp = ServerConfig.AllowSignUp ? "true" : "false";
            fv.showFileChain = "false";
            fv.authList = new List<string>() { "U", "C", "D", "R", "L", "M" };
            fv.publishTime = SystemUtil.accurateToMinute();
            fv.enableFFMPEG = false;
            fv.enableDownloadZip = ServerConfig.EnableDownloadByZip;
            return JsonConvert.SerializeObject(fv);
        }

        [HttpPost]
        public string GetRemainingFolderView([FromForm] string fid, [FromForm] string foldersOffset, [FromForm] string filesOffset)
        {
            //string foldersOffset = Request.Form["foldersOffset"];
            //string filesOffset = Request.Form["filesOffset"];

            if (string.IsNullOrEmpty(fid))
                return "ERROR";

            using var cn = new DapperHelper();

            var vf = FolderDao.queryById(fid, cn);
            if (vf == null)
                return "NOT_FOUND";
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (!accessFolder(vf, account))
                return "notAccess";
            var fv = new RemainingFolderView();
            if (!string.IsNullOrEmpty(foldersOffset))
            {
                try
                {
                    long newFoldersOffset = Convert.ToInt64(foldersOffset);
                    if (newFoldersOffset > 0)
                    {
                        long nfOffset = newFoldersOffset - SELECT_STEP;
                        List<Folder> folders = FolderDao.queryByParentIdSection(fid, nfOffset > 0 ? nfOffset : 0L, nfOffset > 0 ? SELECT_STEP : Convert.ToInt32(newFoldersOffset), cn);
                        List<Folder> fs = new List<Folder>();
                        foreach (var f in folders)
                        {
                            if (accessFolder(f, account))
                                fs.Add(f);
                        }
                        fv.folderList = fs;
                    }
                }
                catch (Exception e)
                {
                    return "ERROR";
                }
            }

            if (!string.IsNullOrEmpty(filesOffset))
            {
                try
                {
                    long newFilesOffset = Convert.ToInt64(filesOffset);
                    if (newFilesOffset > 0)
                    {
                        long nfiOffset = newFilesOffset - SELECT_STEP;
                        fv.fileList = FileDao.queryByParentFolderIdSection(fid, nfiOffset > 0 ? nfiOffset : 0L, nfiOffset > 0 ? SELECT_STEP : Convert.ToInt32(newFilesOffset), cn);
                    }
                }
                catch (Exception e)
                {
                    return "ERROR";
                }
            }

            return JsonConvert.SerializeObject(fv);
        }

        [HttpPost]
        public string SearchInCompletePath([FromForm] string fid, [FromForm] string keyword)
        {
            if (string.IsNullOrEmpty(fid) || string.IsNullOrEmpty(keyword))
                return "ERROR";

            using var cn = new DapperHelper();

            var vf = FolderDao.queryById(fid, cn);
            if (vf == null)
                return "NOT_FOUND";
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (!accessFolder(vf, account))
                return "notAccess";
            var sv = new SearchView();
            keyword = keyword.Trim();
            var sf = new Folder
            {
                FolderId = vf.FolderId,
                FolderName = $"在“{vf.FolderName}”内搜索“{keyword}”的结果...",
                FolderParent = vf.FolderId,
                FolderCreator = "--",
                FolderCreationDate = "--",
                FolderConstraint = vf.FolderConstraint
            };
            sv.folder = sf;
            List<Folder> pl = FolderDao.getParentList(fid, cn);
            pl.Add(vf);
            sv.parentList = pl;
            List<Node> ns = new List<Node>();
            List<Folder> fs = new List<Folder>();
            searchFoldersAndFiles(fid, keyword.ToUpper(), account, ns, fs, cn);
            sv.fileList = ns;
            sv.folderList = fs;
            sv.foldersOffset = 0;
            sv.selectStep = SELECT_STEP;
            if (account != null)
                sv.account = account;
            sv.allowChangePassword = ServerConfig.AllowChangePassword ? "true" : "false";
            // sv.allowSignUp = ServerConfig.AllowSignUp ? "true" : "false";
            // sv.showFileChain = "false";
            sv.authList = new List<string>() { "U", "C", "D", "R", "L", "M", "O" };
            sv.publishTime = SystemUtil.accurateToMinute();
            sv.keyword = keyword;
            sv.enableFFMPEG = false;
            sv.enableDownloadZip = ServerConfig.EnableDownloadByZip;
            return JsonConvert.SerializeObject(sv);
        }

        [HttpPost]
        public string DoLogout()
        {
            HttpContext.Session.Clear();
            return "SUCCESS";
        }

        [HttpPost]
        public string NewFolder([FromForm] string parentId, [FromForm] string folderName, [FromForm] string folderConstraint)
        {
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (string.IsNullOrEmpty(parentId) || string.IsNullOrEmpty(folderName) || string.IsNullOrEmpty(folderConstraint))
                return "errorParameter";
            if (!TextFormatUtil.matcherFolderName(folderName) || folderName.IndexOf(".") == 0)
                return "errorParameter";

            if ("root" == parentId)
                return "noAuthorized";

            using var cn = new DapperHelper();

            Folder parentFolder = FolderDao.queryById(parentId, cn);
            if (parentFolder == null)
                return "errorParameter";
            if (!accessFolder(parentFolder, account))
                return "noAuthorized";
            //if (!ConfigureReader.instance().authorized(account, AccountAuth.CREATE_NEW_FOLDER, this.fu.getAllFoldersId(parentId)))
            //    return "noAuthorized";
            if (FolderDao.queryByParentId(parentId, cn).Any(x => x.FolderName == folderName))
                return "nameOccupied";
            if (FolderDao.countByParentId(parentId, cn) >= 2147483647L)
                return "foldersTotalOutOfLimit";
            Folder f = new Folder();
            int pc = parentFolder.FolderConstraint;
            if (!string.IsNullOrEmpty(folderConstraint))
            {
                try
                {
                    int ifc = Convert.ToInt32(folderConstraint);
                    if (ifc != 0 && account == null)
                        return "errorParameter";
                    if (ifc < pc)
                        return "errorParameter";
                    f.FolderConstraint = ifc;
                }
                catch (Exception e)
                {
                    return "errorParameter";
                }
            }
            else
            {
                return "errorParameter";
            }
            f.FolderId = Guid.NewGuid().ToString();
            f.FolderName = folderName;
            f.FolderCreationDate = SystemUtil.accurateToDay();
            f.FolderCreator = string.IsNullOrEmpty(account) ? "匿名用户" : account;
            f.FolderParent = parentId;

            if (FolderDao.isValidFolder(f, account, cn))
            {
                cn.Insert<Folder>(f);
                return "createFolderSuccess";
            }
            return "cannotCreateFolder";
        }

        [HttpPost]
        public string DeleteFolder([FromForm] string folderId)
        {
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (string.IsNullOrEmpty(folderId) || "root" == folderId)
                return "errorParameter";

            using var cn = new DapperHelper();

            Folder folder = FolderDao.queryById(folderId, cn);
            if (folder == null)
                return "deleteFolderSuccess";
            if (!accessFolder(folder, account))
                return "noAuthorized";
            //if (!ConfigureReader.instance().authorized(account, AccountAuth.DELETE_FILE_OR_FOLDER, this.fu.getAllFoldersId(folder.getFolderParent())))
            //    return "noAuthorized";
            if (folder.FolderStatus > 0)
                return "cannotDeleteFolder";

            if (FileDao.countByParentFolderId(folderId, cn) == 0)
            {
                FolderDao.deleteById(folderId, cn);
                return "deleteFolderSuccess";
            }

            if (FolderDao.deleteFolder(folderId, account, cn))
            {
                FolderDao.deleteAllChildFolder(folderId, account, cn);
                return "deleteFolderSuccess";
            }
            return "cannotDeleteFolder";
        }

        [HttpPost]
        public string RenameFolder([FromForm] string folderId, [FromForm] string newName, [FromForm] string folderConstraint)
        {
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (string.IsNullOrEmpty(folderId) || string.IsNullOrEmpty(newName) || "root" == newName)
                return "errorParameter";
            if (!TextFormatUtil.matcherFolderName(newName) || newName.IndexOf(".") == 0)
                return "errorParameter";

            using var cn = new DapperHelper();

            Folder folder = FolderDao.queryById(folderId, cn);
            if (folder == null)
                return "errorParameter";
            if (!accessFolder(folder, account))
                return "noAuthorized";
            //if (!ConfigureReader.instance().authorized(account, AccountAuth.RENAME_FILE_OR_FOLDER, this.fu.getAllFoldersId(folder.FolderParent)))
            //    return "noAuthorized";
            Folder parentFolder = FolderDao.queryById(folder.FolderParent, cn);
            int pc = parentFolder.FolderConstraint;
            if (!string.IsNullOrEmpty(folderConstraint))
            {
                try
                {
                    int ifc = Convert.ToInt32(folderConstraint);
                    if (ifc != 0 && account == null)
                        return "errorParameter";
                    if (ifc < pc)
                        return "errorParameter";
                    FolderDao.updateFolderConstraintById(folderId, ifc, cn);
                    FolderDao.changeChildFolderConstraint(folderId, ifc, cn);
                    if (folder.FolderName != newName)
                    {
                        if (FolderDao.queryByParentId(folder.FolderParent, cn).Any(x => x.FolderName == newName))
                            return "nameOccupied";

                        if (!FolderDao.updateFolderNameById(folderId, newName, cn))
                            return "errorParameter";
                    }

                    return "renameFolderSuccess";
                }
                catch (Exception e)
                {
                    return "errorParameter";
                }
            }

            return "errorParameter";
        }

        [HttpPost]
        public string DeleteFile([FromForm] string fileId)
        {
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (string.IsNullOrEmpty(fileId))
                return "errorParameter";

            using var cn = new DapperHelper();

            Node node = FileDao.queryById(fileId, cn);
            if (node == null)
                return "deleteFileSuccess";

            Folder f = FolderDao.queryById(node.FileParentFolder, cn);
            if (!accessFolder(f, account))
                return "noAuthorized";
            //if (!ConfigureReader.instance().authorized(account, AccountAuth.DELETE_FILE_OR_FOLDER, this.fu.getAllFoldersId(node.getFileParentFolder()))
            //    return "noAuthorized";
            if (node.FileStatus > 0)
                return "cannotDeleteFile";

            if (string.IsNullOrEmpty(node.FilePath))
                FileDao.deleteById(fileId, cn);
            else
                FileDao.deleteNode(node, account, cn);
            return "deleteFileSuccess";
        }

        [HttpGet("/homeController/[action].do")]
        public async Task<IActionResult> DownloadFile([FromQuery] string fileId, [FromServices] AmazonS3Util s3)
        {
            if (string.IsNullOrEmpty(fileId))
                return NotFound();

            using var cn = new DapperHelper();

            Node node = FileDao.queryById(fileId, cn);
            if (node == null)
                return NotFound();

            var baseUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}";
            if (node.FilePath.StartsWith(baseUrl))
            {
                var objectName = node.FilePath.Replace(baseUrl, "");
                var objectPath = Path.Join(_hostEnvironment.WebRootPath, objectName);
                if (System.IO.File.Exists(objectPath))
                    return File(System.IO.File.OpenRead(objectPath), getFileContentType(node.FileName), node.FileName);
                return NotFound();
            }

            var s3BaseUrl = $"https://{AmazonS3Config.DefaultBucket}.s3.amazonaws.com/";
            if (node.FilePath.StartsWith(s3BaseUrl))
            {
                var objectName = node.FilePath.Replace(s3BaseUrl, "");
                var (existing, response) = await s3.GetObjectAsync(objectName);
                if (existing)
                    return File(response.ResponseStream, getFileContentType(node.FileName), node.FileName);
                return NotFound();
            }

            return Redirect(node.FilePath);
        }

        [HttpPost]
        public string RenameFile([FromForm] string fileId, [FromForm] string newFileName)
        {
            string account = HttpContext.Session.GetString("ACCOUNT");
            if (string.IsNullOrEmpty(fileId) || string.IsNullOrEmpty(newFileName))
                return "errorParameter";
            if (!TextFormatUtil.matcherFileName(newFileName) || newFileName.IndexOf(".") == 0)
                return "errorParameter";

            using var cn = new DapperHelper();

            Node file = FileDao.queryById(fileId, cn);
            if (file == null)
                return "errorParameter";

            Folder folder = FolderDao.queryById(file.FileParentFolder, cn);
            if (!accessFolder(folder, account))
                return "noAuthorized";
            //if (!ConfigureReader.instance().authorized(account, AccountAuth.DELETE_FILE_OR_FOLDER, this.fu.getAllFoldersId(file.getFileParentFolder()))
            //    return "noAuthorized";
            if (file.FileName != newFileName)
            {
                if (FileDao.queryBySomeFolder(fileId, cn).Any(x => x.FileName == newFileName))
                    return "nameOccupied";
                if (!FileDao.updateFileNameById(fileId, newFileName, cn))
                    return "cannotRenameFile";
            }

            return "renameFileSuccess";
        }

        [HttpPost]
        public async Task<string> DoUploadFile([FromForm] string folderId, [FromForm] string fname, [FromForm] string repeType, IFormFile file, [FromServices] AmazonS3Util s3)
        {
            //string folderId = Request.Form["folderId"];
            //string fname = Request.Form["fname"];
            //string repeType = Request.Form["repeType"];
            var account = HttpContext.Session.GetString("ACCOUNT");
            var originalFileName = string.IsNullOrEmpty(fname) ? file.FileName : fname;
            string fileName = originalFileName;
            if (string.IsNullOrEmpty(folderId) || string.IsNullOrEmpty(originalFileName))
                return "uploaderror";
            using var cn = new DapperHelper();
            Folder folder = FolderDao.queryById(folderId, cn);
            if (folder == null)
                return "uploaderror";
            if (!accessFolder(folder, account))
                return "uploaderror";
            long mufs = SystemUtil.getMaxSizeByString(AccountConfig.defaultMaxSize);
            if (mufs >= 0L && file.Length > mufs)
                return "uploaderror";

            List<Node> files = FileDao.queryByParentFolderId(folderId, cn);
            if (files.Any(x => x.FileName == originalFileName))
            {
                if (!string.IsNullOrEmpty(repeType))
                {
                    switch (repeType)
                    {
                        case "skip":
                            return "uploadsuccess";
                        case "cover":
                            //if (!ConfigureReader.instance().authorized(account, AccountAuth.DELETE_FILE_OR_FOLDER, this.fu.getAllFoldersId(folderId)))
                            //    return "uploaderror";
                            foreach (var f in files)
                            {
                                if (f.FileName == originalFileName && !FileDao.deleteNode(f, account, cn))
                                    return "uploaderror";
                            }
                            break;
                        case "both":
                            fileName = TextFormatUtil.getNewNodeName(originalFileName, files);
                            break;
                        default:
                            return "uploaderror";
                    }
                }
                return "uploaderror";
            }

            if (FileDao.countByParentFolderId(folderId, cn) >= 2147483647L)
                return "filesTotalOutOfLimit";

            try
            {
#if DEBUG
                var (success, url) = await SaveFileAsync(file);
#else
                var (success, url) = await s3.PutObjectAsync(file);
#endif
                if (success)
                {
                    string fszie = getFileSize(file.Length);
                    cn.Insert<Node>(new Node()
                    {
                        FileId = Guid.NewGuid().ToString(),
                        FileCreator = string.IsNullOrEmpty(account) ? "匿名用户" : account,
                        FileCreationDate = SystemUtil.accurateToDay(),
                        FileName = fileName,
                        FileParentFolder = folderId,
                        FilePath = url,
                        FileSize = fszie
                    });
                    return "uploadsuccess";
                }
                return "uploaderror";
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return "uploaderror";
            }
        }

        [HttpPost]
        public string CheckUploadFile([FromForm] string folderId, [FromForm] string namelist, [FromForm] string maxSize, [FromForm] string maxFileIndex)
        {
            //string folderId = Request.Form["folderId"];
            string nameList = namelist;
            string maxUploadFileSize = maxSize;
            string maxUploadFileIndex = maxFileIndex;
            var account = HttpContext.Session.GetString("ACCOUNT");
            if (string.IsNullOrEmpty(folderId))
                return "errorParameter";
            if ("root" == folderId)
                return "noAuthorized";
            using var cn = new DapperHelper();
            Folder folder = FolderDao.queryById(folderId, cn);
            if (folder == null)
                return "errorParameter";
            if (!accessFolder(folder, account))
                return "noAuthorized";
            var nameListObj = JsonConvert.DeserializeObject<List<string>>(nameList);
            CheckUploadFileResponse cufr = new CheckUploadFileResponse();
            try
            {
                long mufs = Convert.ToInt64(maxUploadFileSize);
                string mfname = nameListObj[Convert.ToInt32(maxUploadFileIndex)];
                long pMaxUploadSize = SystemUtil.getMaxSizeByString(AccountConfig.defaultMaxSize);
                if (pMaxUploadSize >= 0L && mufs > pMaxUploadSize)
                {
                    cufr.checkResult = "fileTooLarge";
                    cufr.maxUploadFileSize = SystemUtil.formatMaxUploadFileSize(pMaxUploadSize);
                    cufr.overSizeFile = mfname;
                    return JsonConvert.SerializeObject(cufr);
                }
            }
            catch (Exception e)
            {
                return "errorParameter";
            }

            List<string> pereFileNameList = new List<string>();
            foreach (var fileName in nameListObj)
            {
                if (string.IsNullOrEmpty(folderId) || string.IsNullOrEmpty(fileName))
                    return "errorParameter";
                List<Node> files = FileDao.queryByParentFolderId(folderId, cn);
                if (files.Any(x => x.FileName == fileName))
                    pereFileNameList.Add(fileName);
            }
            long estimatedTotal = FileDao.countByParentFolderId(folderId, cn) - pereFileNameList.Count + nameListObj.Count;
            if (estimatedTotal > 2147483647L || estimatedTotal < 0L)
                return "filesTotalOutOfLimit";
            if (pereFileNameList.Count > 0)
            {
                cufr.checkResult = "hasExistsNames";
                cufr.pereFileNameList = pereFileNameList;
            }
            else
            {
                cufr.checkResult = "permitUpload";
                cufr.pereFileNameList = new List<string>();
            }
            return JsonConvert.SerializeObject(cufr);
        }

        [HttpGet, HttpPost]
        public string ping()
        {
            return HttpContext.Session.GetString("ACCOUNT") != null ? "pong" : "";
        }

        [HttpGet, HttpPost]
        public string AskForAllowSignUpOrNot()
        {
            return ServerConfig.AllowSignUp ? "true" : "false";
        }

        private async Task<(bool, string)> SaveFileAsync(IFormFile file)
        {
            if (file == null) return (false, null);
            var fileName = PathFormatter.Format(file.FileName, "/{yyyy}/{mm}/{dd}/{time}{rand:6}");
            var fileType = file.ContentType switch
            {
                _ when file.ContentType.StartsWith("image") => "images",
                _ when file.ContentType.StartsWith("application/msword") || file.ContentType.StartsWith("application/vnd") || file.ContentType.StartsWith("application/pdf") => "docs",
                _ => "files"
            };
            var path = Path.Join(_hostEnvironment.WebRootPath, SystemConfig.UploadPath.Trim('/', '\\'), fileType, fileName).Replace("\\", "/");
            try
            {
                var dir = Path.GetDirectoryName(path);
                var domain = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}";
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                await using var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                await file.CopyToAsync(fs);

                var url = domain + path.Substring(_hostEnvironment.WebRootPath.Length).Replace("\\", "/");
                return (true, url);
            }
            catch (Exception e)
            {
                return (false, e.Message);
            }
        }

        private static string getFileSize(long size)
        {
            int mb = (int)(size / 1048576L);
            return "" + mb;
        }

        private bool accessFolder(Folder f, string account)
        {
            return true;
        }

        private void searchFoldersAndFiles(string fid, string keyword, string account, List<Node> ns, List<Folder> fs, DapperHelper cn)
        {
            var folders = FolderDao.queryByParentId(fid, cn);
            foreach (var f in folders)
            {
                if (accessFolder(f, account))
                {
                    if (f.FolderName.ToUpper().IndexOf(keyword) >= 0)
                    {
                        f.FolderName = f.FolderName;
                        fs.Add(f);
                    }
                    searchFoldersAndFiles(f.FolderId, keyword, account, ns, fs, cn);
                }
            }

            var files = FileDao.queryByParentFolderId(fid, cn);
            foreach (var n in files)
            {
                if (n.FileName.ToUpper().IndexOf(keyword) >= 0)
                {
                    n.FileName = n.FileName;
                    ns.Add(n);
                }
            }
        }

        private string getFileContentType(string fileName)
        {
            string suffix = Path.GetExtension(fileName);
            var provider = new FileExtensionContentTypeProvider();
            var contentType = provider.Mappings[suffix];
            return contentType;
        }
    }
}
